package com.example.examsystem.service;

import com.example.examsystem.dto.PageResponse;
import com.example.examsystem.dto.SubjectDto;
import com.example.examsystem.model.Subject;
import com.example.examsystem.repository.SubjectRepository;
import com.example.examsystem.repository.CategoryRepository;
import com.example.examsystem.repository.QuestionRepository;
import com.example.examsystem.repository.ExamRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 学科服务
 * 处理学科相关的业务逻辑
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SubjectService {
    
    private final SubjectRepository subjectRepository;
    private final CategoryRepository categoryRepository;
    private final QuestionRepository questionRepository;
    private final ExamRepository examRepository;
    
    /**
     * 分页查询学科列表
     * @param page 页码
     * @param size 每页大小
     * @param name 学科名称
     * @param code 学科代码
     * @param status 状态
     * @return 分页学科数据
     */
    public PageResponse<SubjectDto> getSubjects(int page, int size, String name, String code, String status) {
        log.debug("查询学科列表 - 页码: {}, 大小: {}, 筛选条件: 名称={}, 代码={}, 状态={}", 
                page, size, name, code, status);
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<Subject> subjectPage = subjectRepository.findByQuery(name, code, status, pageable);
        
        List<SubjectDto> content = subjectPage.getContent().stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
        
        return new PageResponse<>(
            content,
            subjectPage.getNumber(),
            subjectPage.getSize(),
            subjectPage.getTotalElements(),
            subjectPage.getTotalPages()
        );
    }
    
    /**
     * 获取学科详情
     * @param id 学科ID
     * @return 学科详情
     */
    public SubjectDto getSubject(Long id) {
        log.debug("获取学科详情 - ID: {}", id);
        Subject subject = subjectRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("学科不存在"));
        return convertToDto(subject);
    }
    
    /**
     * 创建学科
     * @param subjectDto 学科数据
     * @return 创建的学科
     */
    @Transactional
    public SubjectDto createSubject(SubjectDto subjectDto) {
        log.debug("创建学科 - 名称: {}, 代码: {}", subjectDto.getName(), subjectDto.getCode());
        
        // 检查学科代码是否已存在
        if (subjectRepository.existsByCode(subjectDto.getCode())) {
            throw new RuntimeException("学科代码已存在");
        }
        
        Subject subject = new Subject();
        subject.setName(subjectDto.getName());
        subject.setCode(subjectDto.getCode());
        subject.setDescription(subjectDto.getDescription());
        subject.setStatus(subjectDto.getStatus());
        subject.setCreatedAt(LocalDateTime.now());
        subject.setUpdatedAt(LocalDateTime.now());
        
        Subject savedSubject = subjectRepository.save(subject);
        log.info("学科创建成功 - ID: {}, 名称: {}", savedSubject.getId(), savedSubject.getName());
        
        return convertToDto(savedSubject);
    }
    
    /**
     * 更新学科
     * @param id 学科ID
     * @param subjectDto 学科数据
     * @return 更新的学科
     */
    @Transactional
    public SubjectDto updateSubject(Long id, SubjectDto subjectDto) {
        log.debug("更新学科 - ID: {}, 名称: {}", id, subjectDto.getName());
        
        Subject subject = subjectRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("学科不存在"));
        
        // 检查学科代码是否已被其他学科使用
        if (!subject.getCode().equals(subjectDto.getCode()) && 
            subjectRepository.existsByCodeAndIdNot(subjectDto.getCode(), id)) {
            throw new RuntimeException("学科代码已存在");
        }
        
        subject.setName(subjectDto.getName());
        subject.setCode(subjectDto.getCode());
        subject.setDescription(subjectDto.getDescription());
        subject.setStatus(subjectDto.getStatus());
        subject.setUpdatedAt(LocalDateTime.now());
        
        Subject updatedSubject = subjectRepository.save(subject);
        log.info("学科更新成功 - ID: {}, 名称: {}", updatedSubject.getId(), updatedSubject.getName());
        
        return convertToDto(updatedSubject);
    }
    
    /**
     * 删除学科
     * @param id 学科ID
     */
    @Transactional
    public void deleteSubject(Long id) {
        log.debug("删除学科 - ID: {}", id);
        
        Subject subject = subjectRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("学科不存在"));
        
        // 检查是否有关联的分类或试题
        // TODO: 添加关联检查
        
        subjectRepository.delete(subject);
        log.info("学科删除成功 - ID: {}, 名称: {}", id, subject.getName());
    }
    
    /**
     * 获取所有激活的学科
     * @return 激活的学科列表
     */
    public List<SubjectDto> getActiveSubjects() {
        log.debug("获取所有激活的学科");
        List<Subject> subjects = subjectRepository.findByStatusOrderByName("ACTIVE");
        return subjects.stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
    }
    
    /**
     * 获取所有启用的学科（不分页）
     * @return 学科列表
     */
    public List<SubjectDto> getAllActiveSubjects() {
        log.debug("获取所有启用的学科");
        List<Subject> subjects = subjectRepository.findByStatusOrderByNameAsc("ACTIVE");
        return subjects.stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
    }
    
    /**
     * 根据代码获取学科
     * @param code 学科代码
     * @return 学科信息
     */
    public SubjectDto getSubjectByCode(String code) {
        log.debug("根据代码获取学科 - 代码: {}", code);
        Subject subject = subjectRepository.findByCode(code)
            .orElseThrow(() -> new RuntimeException("学科不存在"));
        return convertToDto(subject);
    }
    
    /**
     * 批量更新学科状态
     * @param ids 学科ID列表
     * @param status 新状态
     * @return 更新数量
     */
    @Transactional
    public int batchUpdateStatus(List<Long> ids, String status) {
        log.debug("批量更新学科状态 - 数量: {}, 状态: {}", ids.size(), status);
        
        int updatedCount = 0;
        LocalDateTime now = LocalDateTime.now();
        
        for (Long id : ids) {
            try {
                Subject subject = subjectRepository.findById(id).orElse(null);
                if (subject != null) {
                    subject.setStatus(status);
                    subject.setUpdatedAt(now);
                    subjectRepository.save(subject);
                    updatedCount++;
                }
            } catch (Exception e) {
                log.warn("更新学科状态失败 - ID: {}, 错误: {}", id, e.getMessage());
            }
        }
        
        log.info("批量更新学科状态完成 - 更新数量: {}", updatedCount);
        return updatedCount;
    }
    
    /**
     * 检查学科是否可以删除
     * @param id 学科ID
     * @return 是否可以删除
     */
    public boolean canDelete(Long id) {
        log.debug("检查学科是否可以删除 - ID: {}", id);
        
        // 检查是否有关联的分类
        long categoryCount = categoryRepository.countBySubjectId(id);
        if (categoryCount > 0) {
            return false;
        }
        
        // 检查是否有关联的试题
        long questionCount = questionRepository.countBySubjectId(id);
        if (questionCount > 0) {
            return false;
        }
        
        // 检查是否有关联的考试
        long examCount = examRepository.countBySubjectId(id);
        return examCount == 0;
    }
    
    /**
     * 获取学科统计信息
     * @param id 学科ID
     * @return 统计信息
     */
    public Map<String, Object> getSubjectStatistics(Long id) {
        log.debug("获取学科统计信息 - ID: {}", id);
        
        Subject subject = subjectRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("学科不存在"));
        
        Map<String, Object> stats = new HashMap<>();
        stats.put("id", subject.getId());
        stats.put("name", subject.getName());
        stats.put("code", subject.getCode());
        stats.put("categoryCount", categoryRepository.countBySubjectId(id));
        stats.put("questionCount", questionRepository.countBySubjectId(id));
        stats.put("examCount", examRepository.countBySubjectId(id));
        stats.put("createdAt", subject.getCreatedAt());
        stats.put("updatedAt", subject.getUpdatedAt());
        
        return stats;
    }
    
    /**
     * 转换为DTO
     * @param subject 学科实体
     * @return 学科DTO
     */
    private SubjectDto convertToDto(Subject subject) {
        SubjectDto dto = new SubjectDto();
        dto.setId(subject.getId());
        dto.setName(subject.getName());
        dto.setCode(subject.getCode());
        dto.setDescription(subject.getDescription());
        dto.setStatus(subject.getStatus());
        dto.setCreatedAt(subject.getCreatedAt());
        dto.setUpdatedAt(subject.getUpdatedAt());
        
        // 设置统计信息
        if (subject.getCategories() != null) {
            dto.setCategoryCount(subject.getCategories().size());
        }
        if (subject.getQuestions() != null) {
            dto.setQuestionCount(subject.getQuestions().size());
        }
        if (subject.getExams() != null) {
            dto.setExamCount(subject.getExams().size());
        }
        
        return dto;
    }
    
    /**
     * 转换为实体
     * @param dto 学科DTO
     * @return 学科实体
     */
    private Subject convertToEntity(SubjectDto dto) {
        Subject subject = new Subject();
        subject.setName(dto.getName());
        subject.setCode(dto.getCode());
        subject.setDescription(dto.getDescription());
        subject.setStatus(dto.getStatus() != null ? dto.getStatus() : "ACTIVE");
        subject.setCreatedAt(LocalDateTime.now());
        subject.setUpdatedAt(LocalDateTime.now());
        return subject;
    }
}


